<script lang="ts">
	import { onMount, onDestroy } from 'svelte';
	import type { Placement, TriggerType, TooltipInstance } from './types';

	// 组件属性定义
	export let content = '';
	export let placement: Placement = 'top';
	export let trigger: TriggerType = 'hover';
	export let delay = 200;
	export let showArrow = true;
	export let customClass = '';

	// 声明事件回调
	export let onShow: (() => void) | undefined = undefined;
	export let onHide: (() => void) | undefined = undefined;
	export let onToggle: ((visible: boolean) => void) | undefined = undefined;

	let triggerRef: HTMLElement;
	let tooltipNode: HTMLElement | null = null;
	let contentSlot: HTMLElement | null = null;
	let isVisible = false;
	let timeoutId: NodeJS.Timeout | null = null;
	let resizeObserver: ResizeObserver | null = null;

	// 创建Tooltip DOM元素（挂载到body）
	onMount(() => {
		// 仅在浏览器环境执行DOM操作
		if (typeof document === 'undefined' || typeof window === 'undefined') return;

		// 创建tooltip容器（直接挂载到body）
		tooltipNode = document.createElement('div');
		tooltipNode.className = `tooltip-content tooltip-${placement} ${customClass}`;

		// 设置基础样式（仅设置必要的动态样式）
		Object.assign(tooltipNode.style, {
			display: 'none',
			opacity: '0',
			transition: `opacity ${delay}ms ease`,
			position: 'fixed',
			zIndex: '9999',
			pointerEvents: 'auto'
		});

		// 创建内容容器
		const contentNode = document.createElement('div');
		contentNode.className = 'tooltip-inner';

		// 优先使用插槽内容，否则使用content属性
		if (contentSlot) {
			contentNode.innerHTML = contentSlot.innerHTML;
		} else {
			contentNode.innerHTML = content;
		}
		tooltipNode.appendChild(contentNode);

		// 创建箭头元素（根据showArrow属性）
		if (showArrow) {
			createArrowElement();
		}

		// 添加到body
		document.body.appendChild(tooltipNode);

		// 初始化ResizeObserver
		resizeObserver = new ResizeObserver(updatePosition);
		if (triggerRef) {
			resizeObserver.observe(triggerRef);
		}

		// 添加事件监听
		setupEventListeners();
	});

	onDestroy(() => {
		// 清理定时器
		if (timeoutId) clearTimeout(timeoutId);

		// 移除事件监听
		removeEventListeners();

		// 断开ResizeObserver（添加null检查）
		if (resizeObserver) {
			resizeObserver.disconnect();
			resizeObserver = null;
		}

		// 从body移除tooltip元素（添加null检查）
		if (tooltipNode && tooltipNode.parentNode === document.body) {
			document.body.removeChild(tooltipNode);
			tooltipNode = null;
		}
	});

	// 响应式更新内容
	$: if (tooltipNode) {
		const contentNode = tooltipNode.querySelector('.tooltip-inner') as HTMLElement;
		if (contentNode) {
			if (contentSlot) {
				contentNode.innerHTML = contentSlot.innerHTML;
			} else {
				contentNode.innerHTML = content;
			}
		}
	}

	// 响应式更新箭头
	$: if (tooltipNode && showArrow) {
		createArrowElement();
		updatePosition();
	}

	// 响应式更新位置
	$: if (isVisible && tooltipNode) {
		updatePosition();
	}

	// 创建箭头元素
	function createArrowElement() {
		if (!tooltipNode) return;

		// 移除现有箭头
		const existingArrow = tooltipNode.querySelector('.tooltip-arrow');
		if (existingArrow) {
			tooltipNode.removeChild(existingArrow);
		}

		// 创建新箭头（如果showArrow为true）
		if (showArrow) {
			const arrowNode = document.createElement('div');
			const basePlacement = placement.split('-')[0];
			arrowNode.className = `tooltip-arrow tooltip-arrow-${basePlacement}`;
			tooltipNode.appendChild(arrowNode);
		}
	}

	// 设置事件监听
	function setupEventListeners() {
		if (!triggerRef || typeof document === 'undefined') return;

		// 触发元素事件
		triggerRef.addEventListener('mouseenter', handleMouseEnter);
		triggerRef.addEventListener('mouseleave', handleMouseLeave);
		triggerRef.addEventListener('click', handleClick);

		// 全局点击事件（点击外部关闭）
		document.addEventListener('click', handleDocumentClick);

		// tooltip自身的hover事件（防止快速移开）
		if (tooltipNode) {
			tooltipNode.addEventListener('mouseenter', handleTooltipMouseEnter);
			tooltipNode.addEventListener('mouseleave', handleTooltipMouseLeave);
		}
	}

	// 移除事件监听
	function removeEventListeners() {
		if (!triggerRef || typeof document === 'undefined') return;

		triggerRef.removeEventListener('mouseenter', handleMouseEnter);
		triggerRef.removeEventListener('mouseleave', handleMouseLeave);
		triggerRef.removeEventListener('click', handleClick);

		document.removeEventListener('click', handleDocumentClick);

		if (tooltipNode) {
			tooltipNode.removeEventListener('mouseenter', handleTooltipMouseEnter);
			tooltipNode.removeEventListener('mouseleave', handleTooltipMouseLeave);
		}
	}

	// 鼠标进入触发元素
	function handleMouseEnter() {
		if (trigger === 'hover') {
			if (timeoutId) clearTimeout(timeoutId);

			timeoutId = setTimeout(() => {
				showTooltip();
			}, delay);
		}
	}

	// 鼠标离开触发元素
	function handleMouseLeave() {
		if (trigger === 'hover') {
			if (timeoutId) clearTimeout(timeoutId);

			timeoutId = setTimeout(() => {
				hideTooltip();
			}, delay);
		}
	}

	// tooltip自身hover
	function handleTooltipMouseEnter() {
		if (trigger === 'hover' && timeoutId) {
			clearTimeout(timeoutId);
		}
	}

	// tooltip自身mouseleave
	function handleTooltipMouseLeave() {
		if (trigger === 'hover') {
			hideTooltip();
		}
	}

	// 点击触发元素
	function handleClick() {
		if (trigger === 'click') {
			if (isVisible) {
				hideTooltip();
			} else {
				showTooltip();
			}
		}
	}

	// 点击外部关闭
	function handleDocumentClick(e: MouseEvent) {
		if (
			trigger === 'click' &&
			isVisible &&
			triggerRef &&
			!triggerRef.contains(e.target as Node) &&
			tooltipNode &&
			!tooltipNode.contains(e.target as Node)
		) {
			hideTooltip();
		}
	}

	// 显示Tooltip
	function showTooltip() {
		if (!tooltipNode) return;

		// 确保箭头已创建
		if (showArrow && !tooltipNode.querySelector('.tooltip-arrow')) {
			createArrowElement();
		}

		isVisible = true;
		tooltipNode.style.display = 'block';

		// 延迟显示动画（避免闪烁）
		setTimeout(() => {
			if (tooltipNode) {
				tooltipNode.style.opacity = '1';
			}
		}, 10);

		// 更新位置（基于触发元素定位）
		updatePosition();

		// 触发事件
		if (onShow) onShow();
		if (onToggle) onToggle(true);
	}

	// 隐藏Tooltip
	function hideTooltip() {
		if (!tooltipNode) return;

		isVisible = false;
		tooltipNode.style.opacity = '0';

		// 延迟隐藏（等待动画完成）
		setTimeout(() => {
			if (tooltipNode) {
				tooltipNode.style.display = 'none';
			}
		}, 200);

		// 触发事件
		if (onHide) onHide();
		if (onToggle) onToggle(false);
	}

	// 更新Tooltip位置（核心逻辑）
	function updatePosition() {
		if (!triggerRef || !tooltipNode || typeof window === 'undefined') return;

		const triggerRect = triggerRef.getBoundingClientRect(); // 触发元素视口位置
		const tooltipRect = tooltipNode.getBoundingClientRect(); // tooltip自身尺寸
		const arrowNode = tooltipNode.querySelector('.tooltip-arrow') as HTMLElement | null;

		let left = 0;
		let top = 0;

		// 根据placement计算位置（基于视口坐标）
		switch (placement) {
			case 'top':
				left = triggerRect.left + triggerRect.width / 2 - tooltipRect.width / 2;
				top = triggerRect.top - tooltipRect.height - 8;
				break;

			case 'top-start':
				left = triggerRect.left;
				top = triggerRect.top - tooltipRect.height - 8;
				break;

			case 'top-end':
				left = triggerRect.right - tooltipRect.width;
				top = triggerRect.top - tooltipRect.height - 8;
				break;

			case 'bottom':
				left = triggerRect.left + triggerRect.width / 2 - tooltipRect.width / 2;
				top = triggerRect.bottom + 8;
				break;

			case 'bottom-start':
				left = triggerRect.left;
				top = triggerRect.bottom + 8;
				break;

			case 'bottom-end':
				left = triggerRect.right - tooltipRect.width;
				top = triggerRect.bottom + 8;
				break;

			case 'left':
				left = triggerRect.left - tooltipRect.width - 8;
				top = triggerRect.top + triggerRect.height / 2 - tooltipRect.height / 2;
				break;

			case 'left-start':
				left = triggerRect.left - tooltipRect.width - 8;
				top = triggerRect.top;
				break;

			case 'left-end':
				left = triggerRect.left - tooltipRect.width - 8;
				top = triggerRect.bottom - tooltipRect.height;
				break;

			case 'right':
				left = triggerRect.right + 8;
				top = triggerRect.top + triggerRect.height / 2 - tooltipRect.height / 2;
				break;

			case 'right-start':
				left = triggerRect.right + 8;
				top = triggerRect.top;
				break;

			case 'right-end':
				left = triggerRect.right + 8;
				top = triggerRect.bottom - tooltipRect.height;
				break;
		}

		// 边界检查（防止超出视口）
		const viewportWidth = window.innerWidth;
		const viewportHeight = window.innerHeight;

		// 水平边界调整
		if (left < 0) left = 8;
		if (left + tooltipRect.width > viewportWidth) left = viewportWidth - tooltipRect.width - 8;

		// 垂直边界调整
		if (top < 0) top = 8;
		if (top + tooltipRect.height > viewportHeight) top = viewportHeight - tooltipRect.height - 8;

		// 设置最终位置（fixed定位基于视口）
		tooltipNode.style.left = `${left}px`;
		tooltipNode.style.top = `${top}px`;

		// 更新箭头位置
		if (arrowNode && showArrow) {
			updateArrow(arrowNode);
		}
	}

	// 更新箭头位置和样式
	function updateArrow(arrowNode: HTMLElement) {
		if (!arrowNode || !showArrow) return;

		const basePlacement = placement.split('-')[0];
		const subPlacement = placement.split('-')[1] || 'center';

		// 设置箭头位置
		switch (basePlacement) {
			case 'top':
				arrowNode.style.bottom = '-10px';
				arrowNode.style.left =
					subPlacement === 'start'
						? '15px'
						: subPlacement === 'end'
							? 'calc(100% - 20px)'
							: 'calc(50% - 5px)';
				break;
			case 'bottom':
				arrowNode.style.top = '-10px';
				arrowNode.style.left =
					subPlacement === 'start'
						? '10px'
						: subPlacement === 'end'
							? 'calc(100% - 20px)'
							: 'calc(50% - 5px)';
				break;
			case 'left':
				arrowNode.style.right = '-10px';
				arrowNode.style.top =
					subPlacement === 'start'
						? '10px'
						: subPlacement === 'end'
							? 'calc(100% - 20px)'
							: 'calc(50% - 5px)';
				break;
			case 'right':
				arrowNode.style.left = '-10px';
				arrowNode.style.top =
					subPlacement === 'start'
						? '10px'
						: subPlacement === 'end'
							? 'calc(100% - 20px)'
							: 'calc(50% - 5px)';
				break;
		}
	}

	// 暴露给父组件的方法
	export const open: TooltipInstance['open'] = () => {
		showTooltip();
	};

	export const close: TooltipInstance['close'] = () => {
		hideTooltip();
	};

	export const toggleTooltip: TooltipInstance['toggleTooltip'] = () => {
		isVisible ? hideTooltip() : showTooltip();
	};
</script>

<!-- 触发元素容器 -->
<div bind:this={triggerRef} class="tooltip-trigger">
	<slot name="trigger" />
</div>

<!-- 内容插槽（用于获取自定义内容） -->
<div bind:this={contentSlot} style="display: none;">
	<slot name="content">{content}</slot>
</div>

<style scoped lang="scss">
	.tooltip-trigger {
		position: relative;
		display: inline-block;
	}
</style>
